using DA.AnimGraph;
using System;
using System.Collections.Generic;
using System.Text;
using UnityEngine;
using UnityEngine.UIElements;

namespace DA.AnimGraph.Editor {
    internal class BlackboardPane : ContextPaneBase {

        HandleKeeper<AGAHandle_Root> rootHK;
        PaneTitle paneTitle;
        GenericMenuButton menuButton;
        ListView blackboardListView;
        ListView blackboardPreviewListView;

        public BlackboardPane(ContextPaneBase parent) : base(parent) {
            paneTitle = new PaneTitle("Blackboard");
            menuButton = new GenericMenuButton("+");
            BuildMenu();
        }
        protected override void OnSetHandle(AGAHandleBase handle) {
            Debug.Assert(handle is AGAHandle_Root || handle == null);
            if (handle == null) {
                rootHK = default;
                return;
            }
            rootHK = new HandleKeeper<AGAHandle_Root>(handle as AGAHandle_Root);
        }
        protected override void OnClearUI() {
            ageEnv.OnModeChanged -= OnModeChanged;
            Clear();
            blackboardListView?.Clear();
            blackboardListView = null;
        }
        protected override void OnDrawUI() {
            ageEnv.OnModeChanged += OnModeChanged;
            OnModeChanged();
        }
        void OnModeChanged() {
            Clear();
            blackboardListView?.Clear();
            blackboardListView = null;

            switch (ageEnv.ageMode) {
                case AGEMode.Edit:
                    Add(paneTitle);
                    Add(menuButton);
                    BuildBBList();
                    break;
                case AGEMode.Preview:
                    Add(paneTitle);
                    BuildBBPreviewList();
                    break;
            }
        }
        protected override void OnUpdateUI() {
            if (rootHK.isDirty) {
                blackboardListView.Rebuild();
                rootHK.ClearDirty();
            }
        }
        void BuildMenu() {
            // menuButton.AddMenuItem(
            //     ("int", () => AddBlackboardEntry(AGABlackboardType.Int)),
            //     ("float", () => AddBlackboardEntry(AGABlackboardType.Float)),
            //     ("vector2", () => AddBlackboardEntry(AGABlackboardType.Vector2))
            // );
            menuButton.AddMenuItem("int", () => AddBlackboardEntry(AGABlackboardType.Int));
            menuButton.AddMenuItem("float", () => AddBlackboardEntry(AGABlackboardType.Float));
            menuButton.AddMenuItem("vector2", () => AddBlackboardEntry(AGABlackboardType.Vector2));

            var blackboardStructTypes = BlackboardTypeRegister.GetInstance().blackboardStructTypes;
            if (blackboardStructTypes.Count != 0) {
                menuButton.AddMenuSeparator();
            }
            foreach (var structType in blackboardStructTypes) {
                menuButton.AddMenuItem("使用定义的结构体/" + structType.Item1.FullName, () => AddBlackboardEntriesByStruct(structType.Item1));
            }
        }
        void BuildBBList() {
            blackboardListView = new ListView() {
                reorderable = true,
                reorderMode = ListViewReorderMode.Animated,
                fixedItemHeight = 20,
                selectionType = SelectionType.Single,
                showAlternatingRowBackgrounds = AlternatingRowBackground.All,
            };
            blackboardListView.itemIndexChanged += (oldIndex, newIndex) => {
                blackboardListView.Rebuild();
                rootHK.handle.SetDirty();
            };
            blackboardListView.makeItem = () => {
                var field = new BlackboardEntryField(ageContext);
                field.OnDeleteSelf += RemoveBlackboardEntry;
                field.OnValueChange += OnValueChange;
                return field;
            };
            blackboardListView.bindItem += (element, index) => {
                var entry = element as BlackboardEntryField;
                entry.SetData(rootHK.handle.blackboardEntries[index]);
            };
            blackboardListView.itemsSource = rootHK.handle.blackboardEntries;
            Add(blackboardListView);
        }
        void BuildBBPreviewList() {
            blackboardPreviewListView = new ListView() {
                reorderable = false,
                fixedItemHeight = 40,
                selectionType = SelectionType.Single,
                showAlternatingRowBackgrounds = AlternatingRowBackground.All,
            };
            // blackboardPreviewListView.itemIndexChanged += (oldIndex, newIndex) => {
            //     blackboardPreviewListView.Rebuild();
            //     rootHK.handle.SetDirty();
            // };
            blackboardPreviewListView.makeItem = () => {
                var field = new BlackboardEntryFieldPreview(ageEnv);
                return field;
            };
            blackboardPreviewListView.bindItem += (element, index) => {
                var field = element as BlackboardEntryFieldPreview;
                var e = rootHK.handle.blackboardEntries[index];
                field.SetData(e.type, e.name);
            };
            blackboardPreviewListView.itemsSource = rootHK.handle.blackboardEntries;
            Add(blackboardPreviewListView);
        }
        private void OnValueChange(AGA_Blackboard.Entry entry) {
            rootHK.handle.ModifyBlackboardEntry(entry.uuid, entry);
        }
        void RemoveBlackboardEntry(AUID uuid) {
            rootHK.handle.RemoveBlackboardEntry(uuid);
            ageContext.serviceManager.GetService<ShowInspectorService>().ClearInspector();
        }
        void AddBlackboardEntry(AGABlackboardType type) {
            rootHK.handle.AddBlackboardEntry(null, type);
        }
        
        /// <summary>
        /// 添加整个struct
        /// </summary>
        void AddBlackboardEntriesByStruct(Type type) {
            var fields = type.GetFields();
            var order = new List<(string, AGABlackboardType, AddBBCode)>(fields.Length);
            foreach (var field in fields) {
                var fieldType = field.FieldType;

                AGABlackboardType fieldTypeEnum = default;
                if (fieldType == typeof(int)) {
                    fieldTypeEnum = AGABlackboardType.Int;
                } else if (fieldType == typeof(float)) {
                    fieldTypeEnum = AGABlackboardType.Float;
                } else if (fieldType == typeof(Vector2) || fieldType == typeof(Unity.Mathematics.float2)) {
                    fieldTypeEnum = AGABlackboardType.Vector2;
                } else {
                    continue;
                }

                // 确认是否已经存在
                AddBBCode code = AddBBCode.unknown;
                var entry = rootHK.handle.GetBlackboardEntryByName(field.Name);
                if (entry == null) {
                    code = AddBBCode.normal;
                } else {
                    if (entry.Value.type == fieldTypeEnum) {
                        code = AddBBCode.ignore;
                    } else {
                        code = AddBBCode.conflict;
                    }
                }

                order.Add((field.Name, fieldTypeEnum, code));
            }
            if (order.Count == 0) {
                return;
            }

            // 弹窗提示
            StringBuilder hint_normal = new StringBuilder();
            StringBuilder hint_ignore = new StringBuilder();
            StringBuilder hint_conflict = new StringBuilder();
            foreach (var iter in order) {
                if (iter.Item3 == AddBBCode.normal) {
                    hint_normal.AppendLine($"({iter.Item2})\t{iter.Item1}");
                } else if (iter.Item3 == AddBBCode.ignore) {
                    hint_ignore.AppendLine($"({iter.Item2})\t{iter.Item1}");
                } else if (iter.Item3 == AddBBCode.conflict) {
                    hint_conflict.AppendLine($"({iter.Item2})\t{iter.Item1}");
                }
            }
            StringBuilder finalString = new StringBuilder();
            if (hint_normal.Length != 0) {
                finalString.AppendLine("即将添加条目：");
                finalString.AppendLine(hint_normal.ToString());
            }
            if (hint_ignore.Length != 0) {
                finalString.AppendLine("条目已存在，将跳过：");
                finalString.AppendLine(hint_ignore.ToString());
            }
            if (hint_conflict.Length != 0) {
                finalString.AppendLine("条目已存在，且类型冲突：");
                finalString.AppendLine(hint_conflict.ToString());
            }

            // var isOk = EditorUtility.DisplayDialog("添加Blackboard条目", finalString.ToString(), "确认添加", "取消");
            // if (isOk) {
            //     foreach (var iter in order) {
            //         if (iter.Item3 == AddBBCode.ignore) {
            //             continue;
            //         }
            //         rootHK.handle.AddBlackboardEntry(iter.Item1, iter.Item2);
            //     }
            // }
            Label finalStringLabel = new Label(finalString.ToString());
            var window = DialogWindow.ShowWindow("添加Blackboard条目");
            window.UseTemplate_3Button("确认添加(重命名冲突条目)", "确认添加(跳过冲突条目)", "取消", finalStringLabel, index => {
                if (index == 1) {
                    foreach (var iter in order) {
                        if (iter.Item3 == AddBBCode.ignore) {
                            continue;
                        }
                        rootHK.handle.AddBlackboardEntry(iter.Item1, iter.Item2);
                    }
                } else if (index == 2) {
                    foreach (var iter in order) {
                        if (iter.Item3 == AddBBCode.ignore || iter.Item3 == AddBBCode.conflict) {
                            continue;
                        }
                        rootHK.handle.AddBlackboardEntry(iter.Item1, iter.Item2);
                    }
                }
            });

        }

        /// <summary>
        /// 添加整个struct时检查每个字段的结果编号
        /// </summary>
        enum AddBBCode {
            unknown, // 初始值，相当于null
            normal = 1, // 原本没有，正常添加
            ignore, // 已经有了，并且类型相同
            error = 20, // 分割线
            conflict, // 已经有了，并且类型不同
        }
    }
}
